package com.bookrecomm.crawler.service.impl;

import com.bookrecomm.crawler.entity.Book;
import com.bookrecomm.crawler.entity.Category;
import com.bookrecomm.crawler.entity.Comment;
import com.bookrecomm.crawler.entity.Tag;
import com.bookrecomm.crawler.service.AbstractBookCrawler;
import com.bookrecomm.crawler.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 当当网图书爬虫实现类
 * 负责爬取当当网的图书信息
 */
@Slf4j
public class DangdangCrawler extends AbstractBookCrawler {

    // 当当网图书列表页URL模板（旧版）
    private static final String OLD_LIST_URL_TEMPLATE = "http://category.dangdang.com/pg%d-cp01.%s.00.00.00.html";
    
    // 当当网畅销书榜单URL模板（新版）
    private static final String BESTSELLER_URL_TEMPLATE = "http://bang.dangdang.com/books/bestsellers/%s-recent30-0-0-%d-1";
    
    // 评论页URL模板
    private static final String COMMENT_URL_TEMPLATE = "http://product.dangdang.com/index.php?r=comment%2Flist&productId=%s&pageIndex=%d&sortType=1&filterType=1";
    
    // 日期格式化
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    
    /**
     * 爬取图书列表页
     * @param url 列表页URL
     * @param pageNum 页码
     * @return 图书详情页URL列表
     */
    @Override
    public List<String> crawlBookListPage(String url, int pageNum) {
        List<String> detailUrls = new ArrayList<>();
        
        // 构造分页URL
        String pageUrl = String.format(url, pageNum);
        log.info("爬取图书列表页: {}", pageUrl);
        
        // 获取页面文档
        Document doc = getDocument(pageUrl);
        if (doc == null) {
            log.error("获取列表页文档失败: {}", pageUrl);
            return detailUrls;
        }
        
        // 解析图书列表
        Elements bookItems = doc.select("ul.bigimg li");
        for (Element item : bookItems) {
            Element linkElement = item.selectFirst("a.pic");
            if (linkElement != null) {
                String detailUrl = linkElement.attr("href");
                if (detailUrl != null && !detailUrl.isEmpty()) {
                    // 确保URL是完整的
                    if (!detailUrl.startsWith("http")) {
                        detailUrl = "http:" + detailUrl;
                    }
                    detailUrls.add(detailUrl);
                    log.debug("找到图书详情页: {}", detailUrl);
                }
            }
        }
        
        log.info("列表页 {} 共找到 {} 本图书", pageUrl, detailUrls.size());
        
        // 随机等待，避免频繁请求
        HttpUtil.randomSleep(1, 3);
        
        return detailUrls;
    }
    
    /**
     * 爬取图书详情页
     * @param url 详情页URL
     * @return 图书实体对象
     */
    @Override
    public Book crawlBookDetailPage(String url) {
        log.info("爬取图书详情页: {}", url);
        
        // 获取页面文档
        Document doc = getDocument(url);
        if (doc == null) {
            log.error("获取详情页文档失败: {}", url);
            return null;
        }
        
        Book book = new Book();
        
        try {
            // 提取图书ID
            String productId = extractProductId(url);
            
            // 提取标题
            Element titleElement = doc.selectFirst("div.name_info h1");
            if (titleElement != null) {
                book.setTitle(titleElement.text().trim());
            }
            
            // 提取作者
            Element authorElement = doc.selectFirst("span.author a");
            if (authorElement != null) {
                book.setAuthor(authorElement.text().trim());
            }
            
            // 提取出版社
            Element publisherElement = doc.selectFirst("span.publisher a");
            if (publisherElement != null) {
                book.setPublisher(publisherElement.text().trim());
            }
            
            // 提取出版日期
            Element publishDateElement = doc.selectFirst("span.publisher_date");
            if (publishDateElement != null) {
                String dateText = publishDateElement.text().trim();
                // 提取日期部分
                Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
                Matcher matcher = pattern.matcher(dateText);
                if (matcher.find()) {
                    String dateStr = matcher.group();
                    try {
                        book.setPublishDate(DATE_FORMAT.parse(dateStr));
                    } catch (ParseException e) {
                        log.error("解析出版日期失败: {}", dateStr, e);
                    }
                }
            }
            
            // 提取ISBN
            Elements productElements = doc.select("ul.key li");
            for (Element element : productElements) {
                String text = element.text();
                if (text.contains("ISBN")) {
                    String isbn = text.replaceAll("ISBN[：:]?\\s*", "").trim();
                    book.setIsbn(isbn);
                    break;
                }
            }
            
            // 提取价格
            Element priceElement = doc.selectFirst("p.price span.price_n");
            if (priceElement != null) {
                String priceText = priceElement.text().trim().replace("¥", "");
                try {
                    book.setPrice(new BigDecimal(priceText));
                } catch (NumberFormatException e) {
                    log.error("解析价格失败: {}", priceText, e);
                }
            }
            
            // 提取页数
            for (Element element : productElements) {
                String text = element.text();
                if (text.contains("页数")) {
                    Pattern pattern = Pattern.compile("\\d+");
                    Matcher matcher = pattern.matcher(text);
                    if (matcher.find()) {
                        String pagesStr = matcher.group();
                        try {
                            book.setPages(Integer.parseInt(pagesStr));
                        } catch (NumberFormatException e) {
                            log.error("解析页数失败: {}", pagesStr, e);
                        }
                    }
                    break;
                }
            }
            
            // 提取封面图片URL
            Element coverElement = doc.selectFirst("div.pic img");
            if (coverElement != null) {
                String coverUrl = coverElement.attr("src");
                if (coverUrl != null && !coverUrl.isEmpty()) {
                    // 确保URL是完整的
                    if (!coverUrl.startsWith("http")) {
                        coverUrl = "http:" + coverUrl;
                    }
                    book.setCoverUrl(coverUrl);
                }
            }
            
            // 提取图书简介
            Element descElement = doc.selectFirst("div.content_show");
            if (descElement != null) {
                book.setDescription(descElement.text().trim());
            }
            
            // 提取目录
            Element catalogElement = doc.selectFirst("div.catalog_show");
            if (catalogElement != null) {
                book.setCatalog(catalogElement.text().trim());
            }
            
            // 提取评分
            Element ratingElement = doc.selectFirst("span.star_show");
            if (ratingElement != null) {
                String ratingText = ratingElement.text().trim();
                Pattern pattern = Pattern.compile("\\d+(\\.\\d+)?");
                Matcher matcher = pattern.matcher(ratingText);
                if (matcher.find()) {
                    String ratingStr = matcher.group();
                    try {
                        book.setRating(new BigDecimal(ratingStr));
                    } catch (NumberFormatException e) {
                        log.error("解析评分失败: {}", ratingStr, e);
                    }
                }
            }
            
            // 提取评分人数
            Element ratingCountElement = doc.selectFirst("a.comment_num");
            if (ratingCountElement != null) {
                String countText = ratingCountElement.text().trim();
                Pattern pattern = Pattern.compile("\\d+");
                Matcher matcher = pattern.matcher(countText);
                if (matcher.find()) {
                    String countStr = matcher.group();
                    try {
                        book.setRatingCount(Integer.parseInt(countStr));
                    } catch (NumberFormatException e) {
                        log.error("解析评分人数失败: {}", countStr, e);
                    }
                }
            }
            
            // 提取分类信息
            List<Category> categories = new ArrayList<>();
            Elements breadcrumbElements = doc.select("div.breadcrumb a");
            int level = 1;
            for (int i = 1; i < breadcrumbElements.size(); i++) { // 跳过首页链接
                Element element = breadcrumbElements.get(i);
                String categoryName = element.text().trim();
                if (!categoryName.isEmpty()) {
                    Category category = new Category();
                    category.setName(categoryName);
                    category.setLevel(level++);
                    categories.add(category);
                }
            }
            book.setCategories(categories);
            
            // 提取标签信息
            List<Tag> tags = new ArrayList<>();
            Elements tagElements = doc.select("div.tag_list a");
            for (Element element : tagElements) {
                String tagName = element.text().trim();
                if (!tagName.isEmpty()) {
                    Tag tag = new Tag();
                    tag.setName(tagName);
                    tag.setHeat(1); // 默认热度
                    tags.add(tag);
                }
            }
            book.setTags(tags);
            
            // 设置默认值
            book.setLanguage("中文");
            book.setStatus(1);
            book.setCreatedAt(new Date());
            book.setUpdatedAt(new Date());
            
            // 爬取评论
            if (productId != null && !productId.isEmpty()) {
                List<Comment> comments = new ArrayList<>();
                for (int i = 1; i <= 3; i++) { // 爬取前3页评论
                    List<String> commentTexts = crawlBookComments(productId, i);
                    for (String commentText : commentTexts) {
                        Comment comment = new Comment();
                        comment.setContent(commentText);
                        comment.setRating(new BigDecimal("4.0")); // 默认评分
                        comment.setLikes(0);
                        comment.setStatus(1);
                        comments.add(comment);
                    }
                }
                book.setComments(comments);
            }
            
            log.info("爬取图书详情成功: {}", book.getTitle());
        } catch (Exception e) {
            log.error("爬取图书详情失败: {}", url, e);
        }
        
        // 随机等待，避免频繁请求
        HttpUtil.randomSleep(2, 5);
        
        return book;
    }
    
    /**
     * 从URL中提取产品ID
     * @param url 详情页URL
     * @return 产品ID
     */
    private String extractProductId(String url) {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(url);
        if (matcher.find()) {
            return matcher.group();
        }
        return null;
    }
    
    /**
     * 爬取图书评论
     * @param bookId 图书ID
     * @param pageNum 页码
     * @return 评论内容列表
     */
    @Override
    public List<String> crawlBookComments(String bookId, int pageNum) {
        List<String> comments = new ArrayList<>();
        
        // 构造评论页URL
        String commentUrl = String.format(COMMENT_URL_TEMPLATE, bookId, pageNum);
        log.info("爬取图书评论: {}", commentUrl);
        
        // 获取评论页内容
        String jsonContent = HttpUtil.doGet(commentUrl);
        if (jsonContent != null && !jsonContent.isEmpty()) {
            // 简单解析JSON，提取评论内容
            // 实际项目中应使用Jackson或Gson等JSON库进行解析
            Pattern pattern = Pattern.compile("\"content\":\"([^\"]*)\"");
            Matcher matcher = pattern.matcher(jsonContent);
            while (matcher.find()) {
                String comment = matcher.group(1);
                // 处理转义字符
                comment = comment.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t");
                comments.add(comment);
            }
        }
        
        log.info("评论页 {} 共找到 {} 条评论", commentUrl, comments.size());
        
        // 随机等待，避免频繁请求
        HttpUtil.randomSleep(1, 2);
        
        return comments;
    }
    
    /**
     * 开始爬取指定分类的图书
     * @param categoryCode 分类代码
     * @param pageStart 起始页码
     * @param pageEnd 结束页码
     */
    @Override
    public void startCrawl(String categoryCode, int pageStart, int pageEnd) {
        log.info("开始爬取分类 {} 的图书，页码范围: {} - {}", categoryCode, pageStart, pageEnd);
        
        int successCount = 0;
        int failCount = 0;
        
        for (int page = pageStart; page <= pageEnd; page++) {
            // 构造分类列表页URL（根据URL格式判断使用哪种模板）
            String listUrl;
            if (categoryCode.contains("bang.dangdang.com")) {
                // 如果用户直接输入了完整URL，则直接使用
                listUrl = categoryCode.replace("page=1", "page=" + page);
            } else if (categoryCode.contains("bestsellers")) {
                // 如果包含bestsellers关键词，使用畅销书榜单模板
                listUrl = String.format(BESTSELLER_URL_TEMPLATE, categoryCode, page);
            } else {
                // 否则使用旧版分类页模板
                listUrl = String.format(OLD_LIST_URL_TEMPLATE, page, categoryCode);
            }
            
            log.info("爬取页面: {}", listUrl);
            
            // 爬取列表页
            List<String> detailUrls = crawlBookListPage(listUrl, page);
            
            // 爬取详情页
            for (String detailUrl : detailUrls) {
                Book book = crawlBookDetailPage(detailUrl);
                if (book != null) {
                    // 保存图书数据
                    boolean success = saveBook(book);
                    if (success) {
                        successCount++;
                        log.info("成功保存图书: {}", book.getTitle());
                    } else {
                        failCount++;
                        log.error("保存图书失败: {}", book.getTitle());
                    }
                } else {
                    failCount++;
                }
            }
            
            log.info("完成第 {} 页爬取，成功: {}，失败: {}", page, successCount, failCount);
        }
        
        log.info("分类 {} 爬取完成，总成功: {}，总失败: {}", categoryCode, successCount, failCount);
    }
}
